package com.xysoft.admin.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.xysoft.admin.common.ElementConst;
import com.xysoft.admin.common.PageModel;
import com.xysoft.admin.common.SessionInfo;
import com.xysoft.admin.dto.ProblemDTO;
import com.xysoft.admin.dto.ProblemDataDTO;
import com.xysoft.admin.dto.ProblemNumberDTO;
import com.xysoft.admin.dto.SystemTypeDTO;
import com.xysoft.admin.service.IProblemService;
import com.xysoft.model.Organization;
import com.xysoft.model.Problem;
import com.xysoft.model.SystemType;
import com.xysoft.model.User;
import com.xysoft.util.DateUtil;
import com.xysoft.util.FileUtil;
import com.xysoft.util.JsonUtil;
import com.xysoft.util.RequestUtil;
import com.xysoft.util.ZipUtil;

@Component
@SuppressWarnings("unchecked")
public class ProblemServiceImpl extends BaseServiceImpl implements IProblemService {

	@Transactional(readOnly = true)
	public String get(HttpServletRequest request, HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
//		String[] orgStr = sessionInfo.getKeyChar().split(";");
		//获取组织名称
//		List<Organization> organs = this.getBaseDao().find("from Organization o where o.parent = null");
//		Map<Integer, String> organMaps = new HashMap<Integer, String>();
//		for (Organization organ : organs) {
//			organMaps.put(organ.getId(), organ.getName());
//		}
//		List<Organization> organsubs = this.getBaseDao().find("from Organization o where o.parent.id = ?", 
//				organs.get(0).getId());
//		for (Organization organ : organsubs) {
//			organMaps.put(organ.getId(), organ.getName());
//		}
		int page = Integer.valueOf(RequestUtil.getValue(request, "page"));
		int limit = Integer.valueOf(RequestUtil.getValue(request, "limit"));
		//获取类型
		List<SystemType> types = this.getBaseDao().find("from SystemType s where s.deleted = 0 and s.belong = ? order by s.id asc", 
				ElementConst.PROBLEMLEVETYPE);
		Map<Integer, String> typeMaps = new HashMap<Integer, String>();
		for (SystemType type : types) {
			typeMaps.put(type.getId(), type.getName());
		}
		String hql = "from Problem p where p.deleted = 0";
		List<Object> values = new ArrayList<Object>();
		hql = hql + " and p.organization.id = ?";
		Organization organ = (Organization)this.getBaseDao().get(Organization.class, sessionInfo.getOrgId());
		values.add(this.getRootOrgan(organ).getId());
//		if (orgStr.length >= 2) {
//			values.add(orgStr[0] + ";" + orgStr[1] + ";");
//		} else {
//			values.add(orgStr[0] + ";");
//		}
		if (sessionInfo.getUser().isLimited()) {
			hql = hql + " and p.user.id = ?";
			values.add(sessionInfo.getUser().getId());
		}
		String number = RequestUtil.getValue(request, "number");
		if (number != null) {
			hql = hql + " and p.number like ?";
			values.add("%" + number + "%");
		}
		String title = RequestUtil.getValue(request, "title");
		if (title != null) {
			hql = hql + " and p.title like ?";
			values.add("%" + title + "%");
		}
		String sclassifyID = RequestUtil.getValue(request, "sclassifyID");
		if (sclassifyID != null && !"-1".equals(sclassifyID)) {
			hql = hql + " and p.classify.id = ?";
			values.add(Integer.valueOf(sclassifyID));
		}
		String auto = RequestUtil.getValue(request, "auto");
		if (auto != null && !"-1".equals(auto)) {
			hql = hql + " and p.auto = ?";
			values.add(Boolean.valueOf(auto));
		}
		String belong = RequestUtil.getValue(request, "belong");
		if (belong != null && !"-1".equals(belong)) {
			hql = hql + " and p.belong = ?";
			values.add(Integer.valueOf(belong));
		}
		hql = hql + " order by p.number desc";
		List<Problem> problems = this.getBaseDao().find(hql, page, limit, values);
		List<ProblemDTO> dtos = new ArrayList<ProblemDTO>();
		for (Problem problem : problems) {
			ProblemDTO dto = new ProblemDTO();
			BeanUtils.copyProperties(problem, dto);
			int typeId = problem.getClassify().getId(); 
			dto.setSclassifyID(typeId);
			dto.setSclassify(typeMaps.get(typeId));
			dto.setSuser(problem.getUser().getNickName());
			dto.setSacDate(DateUtil.format(problem.getAcDate()));
			dto.setScreateDate(DateUtil.format(problem.getCreateDate()));
			dto.setSupdateDate(DateUtil.format(problem.getUpdateDate()));
			dto.setSorgan(problem.getOrganization().getName());
			dtos.add(dto);
		}
		long count = this.getBaseDao().count("select count(*) " + hql, values);
		PageModel pm = new PageModel();
		pm.setTotal(count);
		pm.setDatas(dtos);
		return JsonUtil.toStringFromObject(pm);
	}
	
	private Organization getRootOrgan(Organization organ) {
		if (organ.getKeyChar().split(";").length <= 2) return organ;
		else return getRootOrgan(organ.getParent());
	}

	@Transactional
	public String getType() {
		List<SystemType> types = this.getBaseDao().find("from SystemType s where s.belong = ?", 
				ElementConst.PROBLEMLEVETYPE);
		List<SystemTypeDTO> dtos = new ArrayList<SystemTypeDTO>();
		for (SystemType type : types) {
			SystemTypeDTO dto = new SystemTypeDTO();
			dto.setId(type.getId());
			dto.setName(type.getName());
			dtos.add(dto);
		}
		return JsonUtil.toString(dtos);
	}
	
	@Transactional
	public String getAllType() {
		List<SystemType> types = this.getBaseDao().find("from SystemType s where s.belong = ?", 
				ElementConst.PROBLEMLEVETYPE);
		List<SystemTypeDTO> dtos = new ArrayList<SystemTypeDTO>();
		SystemTypeDTO dtoTemp = new SystemTypeDTO();
		dtoTemp.setId(-1);
		dtoTemp.setName("全部");
		dtos.add(dtoTemp);
		for (SystemType type : types) {
			SystemTypeDTO dto = new SystemTypeDTO();
			dto.setId(type.getId());
			dto.setName(type.getName());
			dtos.add(dto);
		}
		return JsonUtil.toString(dtos);
	}

	@Transactional
	public Map<String, Object> addOrModify(HttpServletRequest request,
			HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String id = RequestUtil.getValue(request, "id");
		Problem problem = null;
		if (id == null || "".equals(id)) {
			problem = new Problem();
			String[] orgStr = sessionInfo.getKeyChar().split(";");
			Organization organ = null;
			if (orgStr.length > 2) {
				organ = (Organization)this.getBaseDao().get(Organization.class, Integer.valueOf(orgStr[2]));
			} else {
				organ = (Organization)this.getBaseDao().get(Organization.class, sessionInfo.getOrgId());
			}
			problem.setOrganization(organ);
			problem.setAc(0);
			problem.setCreateDate(new Date());
			problem.setAcDate(new Date());
			problem.setDeleted(false);
			problem.setSubmit(0);
			problem.setUpdateDate(new Date());
			User user = (User)this.getBaseDao().get(User.class, sessionInfo.getUser().getId());
			problem.setUser(user);
		} else {
			problem = (Problem)this.getBaseDao().get(Problem.class, Integer.parseInt(id));
			if (problem.isDeleted()) return null;
			if (problem.getState() != 3 && "3".equals(RequestUtil.getValue(request, "state"))) {
				FileUtil.removeDir(ElementConst.PROBLEMDATAPATH + File.separator + problem.getId());
			}
		}
		problem.setAuthor(RequestUtil.getValue(request, "author"));
		problem.setAuto(Boolean.valueOf(RequestUtil.getValue(request, "auto")));
		problem.setBelong(Integer.valueOf(RequestUtil.getValue(request, "belong")));
		SystemType type = (SystemType)this.getBaseDao().get(SystemType.class, 
				Integer.parseInt(RequestUtil.getValue(request, "sclassifyID")));
		if (type.isDeleted() || !ElementConst.PROBLEMLEVETYPE.equals(type.getBelong())) return null;
		problem.setClassify(type);
		problem.setDifficulty(Integer.parseInt(RequestUtil.getValue(request, "difficulty")));
		problem.setMemoryLimit(Integer.valueOf(RequestUtil.getValue(request, "memoryLimit")));
		problem.setTimeLimit(Integer.parseInt(RequestUtil.getValue(request, "timeLimit")));
		problem.setNumber(RequestUtil.getValue(request, "number"));
		problem.setRemark(RequestUtil.getValue(request, "remark"));
		problem.setSource(RequestUtil.getValue(request, "source"));
		problem.setState(Integer.valueOf(RequestUtil.getValue(request, "state")));
		problem.setTitle(RequestUtil.getValue(request, "title"));
		problem.setDescription(RequestUtil.getValue(request, "description"));
		problem.setInput(RequestUtil.getValue(request, "input"));
		problem.setOutput(RequestUtil.getValue(request, "output"));
		problem.setHint(RequestUtil.getValue(request, "hint"));
		problem.setStandardProgram(RequestUtil.getValue(request, "standardProgram"));
		problem.setSampleInput(RequestUtil.getValue(request, "sampleInput"));
		problem.setSampleOutput(RequestUtil.getValue(request, "sampleOutput"));
		this.getBaseDao().save(problem);
		Map<String,Object> modelMap = new HashMap<String,Object>(3);
		modelMap.put("success", true);
		modelMap.put("title", "保存成功！");
		modelMap.put("msg", "");
		return modelMap;
	}

	@Transactional
	public String getNumber(HttpServletRequest request, HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
//		String[] orgStr = sessionInfo.getKeyChar().split(";");
		String hql = "from Problem p where p.deleted = 0";
		List<Object> values = new ArrayList<Object>();
		Organization organ = (Organization)this.getBaseDao().get(Organization.class, sessionInfo.getOrgId());
		hql = hql + " and p.organization.id = ?";
		values.add(this.getRootOrgan(organ).getId());
//		if (orgStr.length >= 2) {
//			hql = hql + " and p.organization.keyChar = ?";
//			values.add(orgStr[0] + ";" + orgStr[1] + ";");
//		}
		String query = RequestUtil.getValue(request, "query");
		if (query != null) {
			hql = hql + " and p.number like ?";
			values.add("%" + query + "%");
		}
		List<Problem> problems = this.getBaseDao().find(hql, values);
		List<ProblemNumberDTO> dtos = new ArrayList<ProblemNumberDTO>();
		for (Problem problem : problems) {
			ProblemNumberDTO dto = new ProblemNumberDTO();
			dto.setId(problem.getId());
			dto.setNumber(problem.getNumber());
			dto.setTitle(problem.getTitle());
			dtos.add(dto);
		}
		return JsonUtil.toString(dtos);
	}

	@Transactional
	public boolean data(HttpServletRequest request, HttpSession session) throws Exception {
		request.setCharacterEncoding("UTF-8");
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String isStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(isStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return false;
		String targetFile = ElementConst.PROBLEMDATAPATH + File.separator + isStr;
		File target = new File(targetFile);
		if (!target.exists()) target.mkdirs();
		MultipartHttpServletRequest mulrequest = (MultipartHttpServletRequest)request;
		List<MultipartFile> files = mulrequest.getFiles("file");
		for(MultipartFile mfile: files){
			CommonsMultipartFile file = (CommonsMultipartFile)mfile;
			DiskFileItem fileItem = (DiskFileItem) file.getFileItem();
			try {
				File fr = new File(targetFile + File.separator + fileItem.getName());
				FileCopyUtils.copy(file.getBytes(), fr);
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}
		}
		if (target.listFiles().length > 0 && problem.getState() == 3) {
			problem.setState(2);
			this.getBaseDao().save(problem);
		}
		return true;
	}

	@Transactional
	public String getData(HttpServletRequest request, HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String isStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(isStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return null;
		File target = new File(ElementConst.PROBLEMDATAPATH + File.separator + isStr);
		if (!target.exists()) target.mkdirs();
		File[] files = target.listFiles();
		List<ProblemDataDTO> dtos = new ArrayList<ProblemDataDTO>();
		for (File file : files) {
			ProblemDataDTO dto = new ProblemDataDTO();
			dto.setName(file.getName());
			dto.setDate(DateUtil.format(new Date(file.lastModified())));
			dto.setSize(getLength(file.length()));
			dtos.add(dto);
		}
		return JsonUtil.toString(dtos);
	}
	
	private String getLength(long len) {
		if (len < 1024) {
			return "1KB";
		} else {
			return (int)(len/1000) + "KB";
		}
	}

	@Transactional
	public Map<String, Object> removeData(HttpServletRequest request,
			HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String isStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(isStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return null;
		List<String> filenames = new ArrayList<String>();
		String fileStr = RequestUtil.getValue(request, "dataId");
		String temp = fileStr.substring(0, fileStr.indexOf("."));
		filenames.add(temp + ".in");
		filenames.add(temp + ".out");
		for (String filename: filenames) {
			File target = new File(ElementConst.PROBLEMDATAPATH + File.separator + isStr + File.separator + filename);
			if (target.exists()) target.delete();
		}
		File dir = new File(ElementConst.PROBLEMDATAPATH + File.separator + isStr);
		if (dir.listFiles().length < 1) {
			problem.setState(3);
			this.getBaseDao().save(problem);
		}
		Map<String,Object> modelMap = new HashMap<String,Object>(2);
		modelMap.put("success", true);
		modelMap.put("title", "保存成功！");
		modelMap.put("msg", "");
		return modelMap;
	}

	@Transactional
	public Map<String, Object> getDetail(HttpServletRequest request,
			HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String isStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(isStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return null;
		File target = new File(ElementConst.PROBLEMDATAPATH + File.separator + isStr + File.separator 
				+ RequestUtil.getValue(request, "name"));
		if (!target.exists()) return null;
		InputStream in = null;
		Reader rd = null;
		try {
			in = new FileInputStream(target);
			rd = new InputStreamReader(in, "GB2312");
	        int c = 0;
	        StringBuffer temp = new StringBuffer();
	        while ((c = rd.read()) != -1) {
	            temp.append((char) c);
	        }
	        Map<String,Object> modelMap = new HashMap<String,Object>(2);
	        modelMap.put("content", temp.toString());
	        modelMap.put("success", true);
	        return modelMap;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (in != null) in.close();
				if (rd != null) rd.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		return null;
	}

	@Transactional
	public Map<String, Object> saveDetail(HttpServletRequest request,
			HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String isStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(isStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return null;
		String fileStr = ElementConst.PROBLEMDATAPATH + File.separator + isStr + File.separator 
				+ RequestUtil.getValue(request, "name");
		File target = new File(fileStr);
		if (!target.exists()) return null;
		PrintWriter pw = null;
		try {
			pw = new PrintWriter(fileStr, "GB2312");
			pw.write(RequestUtil.getValue(request, "content"));
			Map<String,Object> modelMap = new HashMap<String,Object>(3);
	        modelMap.put("success", true);
	        modelMap.put("title", "保存成功！");
	        modelMap.put("msg", "");
	        return modelMap;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (pw != null) {
				pw.close();
			}
		}
		return null;
	}

	@Transactional
	public boolean importData(HttpServletRequest request, HttpSession session) {
		SessionInfo sessionInfo = RequestUtil.getSession(request, session);
		String idStr = RequestUtil.getValue(request, "id");
		Problem problem = (Problem)this.getBaseDao().get(Problem.class, Integer.valueOf(idStr));
		if (problem.isDeleted() || !sessionInfo.getKeyChar().startsWith(problem.getOrganization().getKeyChar()) 
				|| (sessionInfo.getUser().isLimited() 
						&& sessionInfo.getUser().getId() != problem.getUser().getId())) return false;
		String targetFile = ElementConst.PROBLEMDATAPATH + File.separator + "tmp";
		String dateStr = DateUtil.format(new Date(), "yyyyMMddHHmmss");
		String fileName = "";
		String dirStr = targetFile + File.separator + dateStr + File.separator;
		String toStr = ElementConst.PROBLEMDATAPATH + File.separator + idStr + File.separator;
		//压缩文件zip
		File fr = null;
		//解压文件夹
		File dirFile = null;
		try {
			File tFile = new File(targetFile);
			if (!tFile.exists()) tFile.mkdirs();
			MultipartHttpServletRequest mulrequest = (MultipartHttpServletRequest)request;
			List<MultipartFile> files = mulrequest.getFiles("file");
			if (files.size() > 0) {
				CommonsMultipartFile file = (CommonsMultipartFile)files.get(0);
				DiskFileItem fileItem = (DiskFileItem) file.getFileItem();
				fileName = fileItem.getName().substring(fileItem.getName().indexOf("."));
				fr = new File(targetFile + File.separator + dateStr + fileName);
				FileCopyUtils.copy(file.getBytes(), fr);
			}
			ZipUtil.unZip(targetFile + File.separator + dateStr + fileName, dirStr);
			dirFile = new File(dirStr);
			File[] fls = dirFile.listFiles();
			for (File fl : fls) {
				File flOut = new File(toStr + fl.getName());
				FileCopyUtils.copy(fl, flOut);
			}
			File toFile = new File(toStr);
			if (problem.getState() == 3 && toFile.listFiles().length > 0) {
				problem.setState(2);
				this.getBaseDao().save(problem);
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			if (fr != null) FileUtil.delete(fr.getPath());
			if (dirFile != null) FileUtil.removeDir(dirFile.getPath());
		}
		return true;
	}
}
